package com.fang.system.rpc.handler;

import com.fang.system.rpc.model.MyContent;
import com.fang.system.rpc.model.MyHeader;
import com.fang.system.rpc.model.PackageMsg;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;

import java.io.ByteArrayInputStream;
import java.io.ObjectInputStream;
import java.util.List;

/**
 * @author fanglingxiao
 * @version 1.0
 * @description TODO
 * @date 2022/7/17 12:54 上午
 **/
public class ServerDecodeHandler extends ByteToMessageDecoder {
    /**
     * 父类有channelRead读取ByteBuf
     * 当服务端接收到的ByteBuf中可能数据不完成{}代表一个ByteBuf []代表一个请求
     * {[head][body][head][body][head]} {[body][head][body]}
     * 因此会导致不完整的请求体解码出错
     */
    @Override
    protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception {
        int headSize = 110;
        while (byteBuf.readableBytes() >= headSize) {
            // 反序列化解析Header
            byte[] bytes = new byte[headSize];
            // 从哪里读取，读多少，但是readIndex不变
            byteBuf.getBytes(byteBuf.readerIndex(), bytes);
            ByteArrayInputStream in = new ByteArrayInputStream(bytes);
            ObjectInputStream oin = new ObjectInputStream(in);
            MyHeader header = (MyHeader) oin.readObject();
            assert header != null;
            if (byteBuf.readableBytes() < header.getDataLen()) {
                break;
            }
            // 指针移动到body开始的位置
            byteBuf.readBytes(headSize);
            byte[] data = new byte[(int) header.getDataLen()];
            ByteArrayInputStream din = new ByteArrayInputStream(data);
            ObjectInputStream doin = new ObjectInputStream(din);

            MyContent content = (MyContent) doin.readObject();
            list.add(new PackageMsg(header, content));
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        super.exceptionCaught(ctx, cause);
        if (ctx.channel().isActive()) {
            ctx.close();
        }
    }
}
